package com.common.utils;

import com.common.constants.NumberConstantPool;
import com.common.interfaces.MyFunction;
import org.springframework.cglib.beans.BeanMap;

import java.util.HashMap;
import java.util.Map;

/**
 * @Brief 枚举类相关方法
 * @Author chenyl
 * @Date 2023-07-10
 * @Version 1.0.0
 */
public class EnumUtil {

    /**
     * 通过任意值匹配枚举类，并返回对应的枚举值
     *
     * @param clazz 枚举类
     * @param obj   任意值
     * @param <E>   枚举类泛型
     * @return 枚举对象
     */
    public static <E extends Enum<E>> E getEnum(Class<E> clazz, Object obj) {
        for (E e : clazz.getEnumConstants()) {
            BeanMap map = BeanMap.create(e);
            for (Object key : map.keySet()) {
                if (map.get(key).equals(obj)) {
                    return e;
                }
            }
        }
        throw new RuntimeException("未匹配到对应的枚举类");
    }

    /**
     * 通过任意值匹配枚举类的指定属性，并返回对应的枚举值
     * 相比不需要指定属性匹配，会更快更精准的匹配到数据
     *
     * @param clazz    枚举类
     * @param function 指定匹配的属性
     * @param obj      任意值
     * @param <E>      枚举类泛型
     * @return 枚举对象
     */
    public static <E extends Enum<E>> E getEnum(Class<E> clazz, MyFunction<E, ?> function, Object obj) {
        String column = FieldUtil.getColumn(function);
        for (E e : clazz.getEnumConstants()) {
            BeanMap map = BeanMap.create(e);
            if (map.get(column).equals(obj)) {
                return e;
            }
        }
        throw new RuntimeException("未匹配到对应的枚举类");
    }

    /**
     * 通过任意值匹配枚举类的指定属性，并返回指定属性的值
     *
     * @param clazz         枚举类
     * @param function      指定匹配的属性
     * @param obj           任意值
     * @param valueFunction 指定返回的属性
     * @param <E>           枚举类泛型
     * @param <V>           返回的数据类型
     * @return
     */
    public static <E extends Enum<E>, V> V getEnum(Class<E> clazz, MyFunction<E, ?> function, Object obj, MyFunction<E, V> valueFunction) {
        String[] columns = FieldUtil.getColumns(new MyFunction[]{function, valueFunction});
        for (E e : clazz.getEnumConstants()) {
            BeanMap map = BeanMap.create(e);
            if (map.get(columns[0]).equals(obj)) {
                return (V) map.get(columns[1]);
            }
        }
        throw new RuntimeException("未匹配到对应的枚举类");
    }

    /**
     * 指定属性的值为key，将枚举类转换成Map
     * 如果在方法中需要多次通过值匹配枚举类的话，优先推荐此方法
     * 获取到枚举类集合之后，在代码中通过值直接获取数据
     * 这样可以减少因为频繁使用反射带来的时间开销
     *
     * @param clazz       枚举类
     * @param keyFunction 枚举的属性
     * @param <E>         枚举类泛型
     * @param <K>         枚举类属性
     * @return Map<key, Enum>
     */
    public static <E extends Enum<E>, K> Map<K, E> getEnumToMap(Class<E> clazz, MyFunction<E, K> keyFunction) {
        Map<K, E> resultMap = new HashMap<>();
        String column = FieldUtil.getColumn(keyFunction);
        for (E e : clazz.getEnumConstants()) {
            BeanMap map = BeanMap.create(e);
            resultMap.put((K) map.get(column), e);
        }
        return resultMap;
    }

    /**
     * 指定属性的值为key，另一个属性的值为value，将枚举类转换成Map
     * 如果在方法中需要多次通过值匹配枚举类的话，优先推荐此方法
     * 获取到枚举类集合之后，在代码中通过值直接获取数据
     * 这样可以减少因为频繁使用反射带来的时间开销
     *
     * @param clazz         枚举类
     * @param keyFunction   对应的属性的值
     * @param valueFunction 对应的属性的值
     * @param <E>           枚举类泛型
     * @param <K>           枚举类属性
     * @param <V>           枚举类属性
     * @return Map<key, value>
     */
    public static <E extends Enum<E>, K, V> Map<K, V> getEnumToMap(Class<E> clazz, MyFunction<E, K> keyFunction, MyFunction<E, V> valueFunction) {
        Map<K, V> resultMap = new HashMap<>();
        String[] columns = FieldUtil.getColumns(new MyFunction[]{keyFunction, valueFunction});
        for (E e : clazz.getEnumConstants()) {
            BeanMap map = BeanMap.create(e);
            resultMap.put((K) map.get(columns[NumberConstantPool.ZERO]), (V) map.get(columns[NumberConstantPool.ONE]));
        }
        return resultMap;
    }
}
